// Copyright: personal possession of Nguyen Minh Kha
// Description: Game class manage Game control, 
//  Game init, Game loop, Game end, Game event...
// Date time: 07/07/2011(mm/dd/yyyy)
// License: free source
// Version: 1.0
// Writer: Nguyen Minh Kha

#include "Game.h"

// Redefine static variable for Game
// Static memeber in .h file is defined, but static also need memory allocated
Game* Game::gameInstance;

Game::Game(void)
{
}


Game::~Game(void)
{
}


Game::Game(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, 
           int nCmdShow) {
  this->hInstance = hInstance;
  this->hPrevInstance = hPreInstance;
  this->lpCmdLine = lpCmdLine;
  this->nCmdShow = nCmdShow;
  gameInstance = NULL;
}


LRESULT Game::DummyWndProc(HWND hWnd, UINT message, 
                           WPARAM wParam, LPARAM lParam) {  
  if (message == WM_CREATE) {
    // copy message param that include a part of (object) param
    // pass to created window
    CREATESTRUCT *m_lParam = (CREATESTRUCT*)lParam;
    // Set inputed value to window that just created
    SetWindowLong(hWnd, GWL_USERDATA, 
                  (LONG)(m_lParam->lpCreateParams));
    if (!m_lParam->lpCreateParams) {
      Log::Write(L"Error when redirect winproc");
      return DefWindowProc(hWnd, message, wParam, lParam);
    } else {
      gameInstance = (Game*) (GetWindowLong(hWnd, GWL_USERDATA));
      if (gameInstance != NULL) {
        return gameInstance->WndProc( hWnd, message, wParam, lParam );
      } else {
        Log::Write(L"Error when redirect winproc");
        return DefWindowProc(hWnd, message, wParam, lParam);
      }
    }
  }
  if (gameInstance != NULL) {
    return gameInstance->WndProc( hWnd, message, wParam, lParam );
  } else {
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
}


LRESULT Game::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  switch (message) {
    case WM_PAINT: {
      break;
    }
    case WM_CLOSE: {
      int messageBoxResult = 0;
      messageBoxResult = MessageBox(
        hWnd, EXIT_CONFIRM_TEXT, 
        EXIT_CONFIRM_CAPTION,
        MB_OKCANCEL | MB_ICONQUESTION);
      if (messageBoxResult == IDOK) {
        done =1 ;
        PostMessage(hWnd, WM_QUIT, 0, 0); 
      break;
      } else {
        return 0;
      }
    }
    case WM_ACTIVATE: {
      if (Control::control != NULL) {
        Control::control->Acquire();
      }
      break;
    }
    case WM_QUIT: {
      done = 1; // cause exit Game
      break;
    }
  } // end switch
  return DefWindowProc(hWnd, message, wParam, lParam);
}


ATOM Game::RegisterWindowClass() {
  WNDCLASSEX wc; // window class extended
  wc.cbSize = sizeof(wc);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.hInstance = hInstance;
  wc.lpfnWndProc = (WNDPROC)DummyWndProc;
  wc.cbClsExtra = 0; // class extra memory, should be 0
  wc.cbWndExtra = 0; // window extra memory, should be 0
  wc.hIcon = NULL;
  wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
  wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
  wc.lpszMenuName = NULL; // menu pointer
  wc.lpszClassName = WINDOWS_TITLE; // class name
  wc.hIconSm = NULL;
  return RegisterClassEx(&wc);
}


BOOL Game::InitInstance() {
  hWnd = CreateWindow(WINDOWS_TITLE, // class name that register 
                        WINDOWS_TITLE, // window name
                        WS_TILED | WS_SYSMENU | WS_MINIMIZEBOX, 
                        //WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP, // fullscreen
                        //WS_VISIBLE | WS_POPUP, // not topmost
                        CW_USEDEFAULT, // default x
                        CW_USEDEFAULT, // default y
                        SCREEN_WIDTH, // window width
                        SCREEN_HEIGHT, // window height
                        NULL, // Parrent window
                        NULL, // Menu pointer
                        hInstance, 
                        this); // this pointer for using instance wndproc
  if(!hWnd) return FALSE;
  return TRUE;
}


int Game:: Init() {
  done = 0;
  //
  // Init window
  //
  RegisterWindowClass();
  BOOL createdWindow = InitInstance(); // create windows instance
  // Show and update created window
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  int hasWorld = world.Init(hInstance, hWnd);
  if (createdWindow == FALSE || hasWorld == 1) {
    return 1; // fatal error
  }
  return 0;
}


int Game::Run() {
  MSG msg; // represent for window message
  // new seed for random
  srand(static_cast<unsigned int>(time(NULL)));
  // and the world run with it law
  world.Exeute();
  while (done == 0) {
    if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    Sleep(1);
  }
  return 0;
}


int Game::End(int returnValue) {
  world.End();
  return returnValue;
}


int Game::Excute() {
  int initResult = this->Init();
  if (initResult != 0) {
    this->End(0);
    return 1; // fatal error
  }
  int runResult = this->Run();
  return this->End(runResult);
}